package com.media.system.service.impl;

import com.media.system.config.MinioConfig;
import com.media.system.service.FileStorageService;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import jakarta.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeUnit;

/**
 * MinIO文件存储服务实现
 * 
 * @author Claude
 * @since 2024-01-20
 */
@Service
@Slf4j
@ConditionalOnProperty(name = "minio.enabled", havingValue = "true", matchIfMissing = true)
public class MinioFileStorageServiceImpl implements FileStorageService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfig.MinioProperties minioProperties;

    @PostConstruct
    public void init() {
        try {
            // 检查存储桶是否存在，不存在则创建
            boolean exists = minioClient.bucketExists(
                BucketExistsArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .build()
            );
            
            if (!exists) {
                minioClient.makeBucket(
                    MakeBucketArgs.builder()
                        .bucket(minioProperties.getBucketName())
                        .build()
                );
                log.info("创建MinIO存储桶: {}", minioProperties.getBucketName());
            }
        } catch (Exception e) {
            log.error("初始化MinIO存储桶失败: {}", e.getMessage(), e);
        }
    }

    @Override
    public String uploadFile(MultipartFile file, String objectName) {
        try {
            InputStream inputStream = file.getInputStream();
            return uploadFile(inputStream, objectName, file.getContentType(), file.getSize());
        } catch (IOException e) {
            log.error("上传文件失败: {}", e.getMessage(), e);
            throw new RuntimeException("上传文件失败: " + e.getMessage());
        }
    }

    @Override
    public String uploadFile(InputStream inputStream, String objectName, String contentType, long fileSize) {
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .stream(inputStream, fileSize, -1)
                    .contentType(contentType)
                    .build();

            minioClient.putObject(putObjectArgs);
            
            log.info("文件上传成功: {}", objectName);
            return getFileUrl(objectName);
            
        } catch (Exception e) {
            log.error("上传文件到MinIO失败: {}", e.getMessage(), e);
            throw new RuntimeException("上传文件失败: " + e.getMessage());
        }
    }

    @Override
    public boolean deleteFile(String objectName) {
        try {
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .build()
            );
            
            log.info("文件删除成功: {}", objectName);
            return true;
            
        } catch (Exception e) {
            log.error("删除文件失败: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public String getFileUrl(String objectName) {
        return minioProperties.getUrlPrefix() + "/" + minioProperties.getBucketName() + "/" + objectName;
    }

    @Override
    public String getPresignedUrl(String objectName, int expireTime) {
        try {
            return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .expiry(expireTime, TimeUnit.SECONDS)
                    .build()
            );
        } catch (Exception e) {
            log.error("生成预签名URL失败: {}", e.getMessage(), e);
            throw new RuntimeException("生成预签名URL失败: " + e.getMessage());
        }
    }

    @Override
    public boolean fileExists(String objectName) {
        try {
            minioClient.statObject(
                StatObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .build()
            );
            return true;
        } catch (ErrorResponseException e) {
            if ("NoSuchKey".equals(e.errorResponse().code())) {
                return false;
            }
            log.error("检查文件是否存在失败: {}", e.getMessage(), e);
            throw new RuntimeException("检查文件是否存在失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("检查文件是否存在失败: {}", e.getMessage(), e);
            throw new RuntimeException("检查文件是否存在失败: " + e.getMessage());
        }
    }

    @Override
    public long getFileSize(String objectName) {
        try {
            StatObjectResponse statObject = minioClient.statObject(
                StatObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .build()
            );
            return statObject.size();
        } catch (Exception e) {
            log.error("获取文件大小失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取文件大小失败: " + e.getMessage());
        }
    }
}